/*=====================================================================*
 *                   Copyright (C) 2011 Paul Mineiro                   *
 * All rights reserved.                                                *
 *                                                                     *
 * Redistribution and use in source and binary forms, with             *
 * or without modification, are permitted provided that the            *
 * following conditions are met:                                       *
 *                                                                     *
 *     * Redistributions of source code must retain the                *
 *     above copyright notice, this list of conditions and             *
 *     the following disclaimer.                                       *
 *                                                                     *
 *     * Redistributions in binary form must reproduce the             *
 *     above copyright notice, this list of conditions and             *
 *     the following disclaimer in the documentation and/or            *
 *     other materials provided with the distribution.                 *
 *                                                                     *
 *     * Neither the name of Paul Mineiro nor the names                *
 *     of other contributors may be used to endorse or promote         *
 *     products derived from this software without specific            *
 *     prior written permission.                                       *
 *                                                                     *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND              *
 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,         *
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES               *
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE             *
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER               *
 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,                 *
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES            *
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE           *
 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR                *
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF          *
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT           *
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY              *
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE             *
 * POSSIBILITY OF SUCH DAMAGE.                                         *
 *                                                                     *
 * Contact: Paul Mineiro <paul@mineiro.com>                            *
 *=====================================================================*/

#ifndef __SPARSE_VECTOR_H__
#define __SPARSE_VECTOR_H__

#include <boost/unordered_map.hpp>

namespace flassol
{
  class SparseVector
    {
      private:
        boost::unordered_map<unsigned int, float> map;

        template<typename Impl>
        class ElementTemplate
          {
            private:
              Impl&         map;
              unsigned int  x;

            public:
              ElementTemplate (Impl&        _map,
                               unsigned int _x)
                : map (_map),
                  x (_x)
                {
                }

              ElementTemplate&
              operator= (float y)
                {
                  if (y == 0)
                    {
                      typename Impl::iterator z = map.find (x);

                      if (z != map.end ())
                        {
                          map.erase (z);
                        }
                    }
                  else
                    {
                      map[x] = y;
                    }

                  return *this;
                }

              operator float () const
                {
                  typename Impl::const_iterator z = map.find (x);

                  return (z == map.end ()) ? 0 : z->second;
                }
          };

        typedef ElementTemplate<boost::unordered_map<unsigned int, float> >
                Element;
        typedef ElementTemplate<const boost::unordered_map<unsigned int, float> >
                ConstElement;

      public:
        Element
        operator[] (const unsigned int x)
          {
            return Element (map, x);
          }

        const ConstElement
        operator[] (const unsigned int x) const
          {
            return ConstElement (map, x);
          }

        typedef boost::unordered_map<unsigned int, float>::const_iterator 
                const_iterator;
        
        const_iterator
        begin () const 
          {
            return map.begin ();
          }

        const_iterator
        end () const 
          {
            return map.end ();
          }

        bool 
        empty ()
          {
            return map.empty ();
          }

        friend std::ostream&
        operator<< (std::ostream& o,
                    const SparseVector& v)
          {
            for (const_iterator it = v.begin ();
                 it != v.end ();
                 ++it)
              {
                o << "{ " << it->first << ", " << it->second << "}, ";
              }

            return o;
          }
    };
};

#endif // __SPARSE_VECTOR_H__
